// 1.导入 express 模块
const express = require('express');
// 2.创建服务器程序
const app = express();
// 3.导入 第三方 模块
const multer = require('multer') // 上传模块
// 创建一个 设置了保存文件路径的 组件对象
const upload = multer({ dest: 'uploads/' }) // 创建 上传模块 对象，并指定 服务端保存路径

// a.注册 解析 请求报文体 k=v格式数据 到 req.body 来的 中间件！
app.use(express.urlencoded({ extended: false }))
// b.注册 解析 请求报文体 json格式数据 到 req.body 来的 中间件！
app.use(express.json())

// c.自定义中间件：浏览器 请求任何 接口，都会先执行 中间件函数！
app.use(function (req, res, next) {
    next()
})
// 【登录token校验中间件】===============================
// 如果 检测出 请求报文头里 没有token，则 直接报错-> UnauthorizedError！
//                         有token，但 超时了，也 直接报错-> UnauthorizedError！
//                         有token,未超时，就 将 解密后的 用户数据对象 添加到 req.user 属性中！
const jwt = require('express-jwt');
app.use(jwt({ secret: 'abc_dx_1008', algorithms: ['HS256'] }).unless({ path: ['/login'] }))
// =====================================================

// 重要：导入 mysql 连接池
const db = require('./db/index.js')

// c.注册路由-----------------------------------
app.get('/', function (req, res) {
    res.send('欢迎访问~！')
});

// d.登录接口 ----------------------------------
// 数据模板：{uname:'admin',upwd:'123123'}
app.post('/login', function (req, res) {
    // 1.接收用户名和密码
    const usrData = req.body
    // 2.验证 用户名和面
    db.query('select * from users where uname=? and upwd=?', [usrData.uname, usrData.upwd], (err, results) => {
        if (err) {
            return console.log('登录出错啦！')
        }
        // 2.1 如果通过验证，则 生成 加密的token
        if (results.length > 0) {
            // 用户数据对象
            const usrData = results[0] // {id,uname,upwd,nickname,age,gender}
            // 导入 token 包，用来生成 token 
            const jwt = require('jsonwebtoken');
            // 准备 要加密的数据                   {id,uname,upwd:null,nickname,age,gender}
            const usr2 = { ...usrData, upwd: null }
            // 生成 加密 token 字符串
            const token = jwt.sign({ data: usr2 }, 'abc_dx_1008', { expiresIn: 60 * 5 })
            // 响应给 浏览器
            res.send({
                msg: '登录成功~！',
                statuscode: 0,
                token // token: token
            })
        }
        // 2.2 如果未通过验证，则返回 登录失败错误消息
        else {
            res.send({
                msg: '登录失败~！',
                statuscode: 1
            })
        }
    })
})

// ============模拟 CRUD(增删改查)======================
// 0.返回狗狗列表------------------------------
app.get('/list', function (req, res) {
    db.query('select * from dogs', (err, results) => {
        if (err) return console.log('出错啦~！')
        let data = {
            msg: '获取狗狗列表成功',
            statuscode: 0,
            list: results
        }
        res.send(data);
    })
});

// 1.根据id查询数据-----------------------------
// /dog?id=1
app.get('/dog', function (req, res) {

    db.query('select * from dogs where id = ?', req.query.id, (err, results) => {
        if (err) return console.log('新增出错啦~！')
        if (results.length > 0) {
            res.send({
                msg: '查询狗狗成功~！',
                statuscode: 0,
                dog: results[0]
            })
        } else {
            res.send({
                msg: '未找到想要的狗狗~！',
                statuscode: 1
            })
        }
    })
});

// 3.新增接口-----------------------------
// {name:'ruiky',age:2}
app.post('/adddog', function (req, res) {
    let data = req.body
    console.log(data)

    db.query('insert into dogs set ?', data, (err, results) => {
        if (err) {
            console.log('新增出错了~！')
            return console.log(err)
        }

        // 如果 新增成功(受影响行数>=1)
        if (results.affectedRows > 0) {
            res.send({
                msg: '新增狗狗成功~！',
                statuscode: 0,
                newId: results.insertId // 数据库生成的id
            });
        } else {
            res.send({
                msg: '新增狗狗失败~！',
                statuscode: 2
            });
        }
    })
})

// 4.更新接口-----------------------------
// {id:15, name:'小红',age:21}
app.post('/modifydog', function (req, res) {
    let data = req.body
    console.log(data)

    db.query('update dogs set ? where id=?', [data, data.id], (err, results) => {
        if (err) {
            console.log('更新出错了~！')
            return console.log(err)
        }

        // 如果 新增成功(受影响行数>=1)
        if (results.affectedRows > 0) {
            res.send({
                msg: '修改狗狗成功~！',
                statuscode: 0
            });
        } else {
            res.send({
                msg: '修改狗狗失败~！',
                statuscode: 2
            });
        }
    })
})

// ============================================

// 2.服务器端 获取 动态参数 数据！【req.params】
// /dog/1/ruiky/false
app.get('/dog/:id/:name/:gender', function (req, res) {
    console.log('req.params->', req.params) // -> { id: '1', name: 'ruiky', gender: 'false' }
    res.send('狗狗狗');
});


// 4.服务器端 获取 请求报文体 数据- JSON格式！
// uname=james&upwd=12323
app.put('/regdog', function (req, res) {
    console.log(req.body)
    res.send('恭喜您，注册狗狗成功~！')
})

// 5.服务器端 获取 请求报文体 数据- FormData格式！
app.put('/upload', upload.single('headimg'), function (req, res) {
    console.log(req.body)
    console.log(req.file)
    res.send('上传成功啦~！')
})

// 【注册express服务器 全局异常处理中间件】
//  整个服务器端 只要报错(token报错，语法报错...)，就会 到这个中间件来！
app.use((err, req, res, next) => {
    //a.判断 异常对象 是否为 UnauthorizedError ，如果是，则 需要重新登录，如果不是，则返回一个普通错误提示
    if (err.name === 'UnauthorizedError') {
        res.send(401)
        // res.send({
        //     msg: 'token丢失或失效，需要重新登录~！',
        //     statuscode: 4
        // })
    }
    next()
})
// 启动服务器-----------------------------------
app.listen(7788, () => {
    console.log('服务器启动了： http://localhost:7788')
})